<template>
	<div class="base-select w-full">
		<t-select v-model="modelValue" :options="options" :placeholder="placeholder" :popupProps="popupProps" @change="handleChange" @popup-visible-change="onPopupVisibleChange"
			v-bind="$attrs" v-on="$listeners">
			<div v-loading="loading" slot="panelTopContent" style="padding: 12px;border-bottom: 1px solid #e8e8e8;">
				<t-input ref="search" v-model="search" :placeholder="panelHolder" @change="onSearch" />
			</div>
		</t-select>
	</div>
</template>

<script>
	import { debounce } from "@/utils/tool";
	export default {
		props: {
			placeholder: {
				type: String,
				default: "",
			},
			panelHolder: {
				type: String,
				default: "请输入关键词搜索",
			},
			// option字段映射
			keys: {
				type: Object,
				default: () => ({
					label: "name",
					value: "id",
				}),
			},
			// http请求参数的字段名
			searchField: {
				type: String,
				default: "name",
			},
			// 每页显示多少条数据
			pageSize: {
				type: Number,
				default: 15,
			},
			// 未提供接口，则启用本地模式
			httpApi: {
				type: Function,
			},
			staticParam: {
				type: Object,
				default: () => {},
			},
			// 展开面板时是否自动请求数据
			autoRequest: {
				type: Boolean,
				default: true,
			},
			// 源下拉数据
			originOpts: {
				type: Array,
				default: () => [],
			},
			value: true,
		},
		data() {
			return {
				page: 1,
				search: "",
				modelValue: "",
				// 加载状态
				loading: false,
				baseOpts: [...this.originOpts],
				popupProps: { onScrollToBottom: this.onScroll },
				// -----------------------
				resData: {},
			};
		},
		computed: {
			httpParam() {
				return {
					page: this.page,
					perPage: this.pageSize,
					[this.searchField]: this.search,
					...this.staticParam,
				};
			},
			fullOpts() {
				let v = this.value || [];
				const id = this.keys.value;
				v = Array.isArray(v) ? v : [v];
				v = v.filter((item) => item[id]);
				const opts = this.baseOpts.filter((opt) => {
					return v.every((dd) => opt[id] !== dd[id]);
				});
				return [...v, ...opts];
			},
			options() {
				return this.fullOpts.map((opt) => {
					return { label: opt[this.keys.label], value: opt[this.keys.value] };
				});
			},
		},
		methods: {
			handleChange(e) {
				if (this.$attrs.multiple) {
					// 多选
					const arrs = e.map((id) => {
						return this.fullOpts.find((opt) => opt[this.keys.value] == id);
					});
					this.$emit("input", arrs);
				} else {
					// 单选
					const opt = this.fullOpts.find((opt) => opt[this.keys.value] == e);
					this.$emit("input", opt);
				}
			},
			onPopupVisibleChange(e) {
				const timer = setTimeout(() => {
					clearTimeout(timer);
					if (e) this.$refs.search.focus();
				}, 500);
				// ---------------------------------------------------------------------------
				// if (e && this.autoRequest && this.httpApi) this.httpRequest(this.page = 1);
				// ---------------------------------------------------------------------------
				if (e && this.autoRequest && this.httpApi &&
					this.baseOpts.length <= this.originOpts.length
				) this.httpRequest();
			},
			onSearch(v) {
				debounce(() => {
					if (this.httpApi) {
						this.page = 1;
						this.httpRequest();
					} else {
						if (v) {
							this.baseOpts = this.originOpts.filter(
								(item) => item[this.keys.label].includes(v)
							);
						} else {
							this.baseOpts = [...this.originOpts];
						}
					}
				});
			},
			onScroll() {
				// 未提供接口，则启用本地模式
				if (!this.httpApi) return;
				const { loading, options, resData } = this;
				if (loading) return;
				if (options.length >= resData.total) return;
				// -----------------------------------------
				this.page++;
				this.httpRequest();
			},
			httpRequest() {
				this.loading = true;
				this.httpApi(this.httpParam)
					.then(res => {
						res = Array.isArray(res.data) ? res : res.data;
						const { data } = this.resData = res || {};
						if (this.page === 1) {
							this.baseOpts = data;
						} else {
							this.baseOpts = [...this.baseOpts, ...data];
						}
					})
					.finally(() => (this.loading = false));
			},
		},
	};
</script>


<style lang="less" scoped>
</style>